package top.wardyan.base.datasource;

import org.apache.log4j.Logger;

import com.alibaba.druid.filter.config.ConfigTools;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.OrderedFieldContainerFactory;
import com.jfinal.plugin.activerecord.dialect.Dialect;
import com.jfinal.plugin.druid.DruidPlugin;

import top.wardyan.base.config.SystemConfig;

/**
 * 抽象类: 数据源 <br>
 * 与Base***的区别: 抽象类中肯定有abstract未实现方法; Base类中更大可能地已经全部实现了 <br>
 * 注意: 本抽象类的子类不包括REDIS相关. REDIS的连接方式跟本类的子类的都不同(目前考虑子类为:sqlserver, mysql, sqlite)<br>
 * 更新日志: <br>
 * V2 2019年2月16日 从原BaseDatasource中重建并抽取通用属性方法, 并改名Abstract***<br>
 * ATTENTION: 最终类应该加上一个静态方法:getInstance
 * @author ward 
 * @version V2 / 2019年2月16日
 */
public abstract class AbstractDatasource{
	
	/** 日志记录器 **/
	protected static Logger log = Logger.getLogger(AbstractDatasource.class);
	
	protected DruidPlugin 			dp;
	protected ActiveRecordPlugin 	arp;
	//protected String SQLSERVER_URL = "jdbc:sqlserver://{localhost}:{port}; DatabaseName = {databasename}";
	
	
	/** 将model映射 **/
	protected abstract void mapping();
	
	/** 获取驱动 **/
	protected abstract String setDriver();
	
	/** 获取方言 **/
	protected abstract Dialect setDialect();
	
	/** 设定连接字符串 其中3个要素:路径用{localhost}, 端口用{port}, 数据库名哟年{databasename} **/
	protected abstract String setJDBCUrl();
	
	/** 设置数据集中的column是否按照数据库中定义的顺序. 默认是用HashMap的顺序. 如果改为true, 则返回的数据集的列顺序跟数据库定义的一样 **/
	protected Boolean setOrderColumn() {
		return false;
	}
	
	/**
	 * 构造函数
	 * @param address			地址 / 路径
	 * @param port				端口
	 * @param dbName			数据库名
	 * @param user				用户名
	 * @param password			密码
	 * @param arpName 			ARP名称
	 * @throws RuntimeException	如果连接出错
	 */
	protected AbstractDatasource(	String	address, 
									Integer	port, 
									String	dbName, 
									String	user, 
									String	password, 
									String	arpName) throws RuntimeException{
		if(password.length() >= 32) {
			try {
				password = ConfigTools.decrypt(SystemConfig.PublicKey, password);
			} catch (Exception e) {
				log.error(e);
			}
		}
		try{
			dp = new DruidPlugin(this.setJDBCUrl().replace("{localhost}",		address)
								 				   .replace("{port}", 			port != null ? port.toString() : "")
								 				   .replace("{databasename}",	dbName),
								 user,
								 password,
								 this.setDriver());
			
			arp = new ActiveRecordPlugin(arpName, dp);
			arp.setDialect(this.setDialect());	// 方言
			if(this.setOrderColumn())
				arp.setContainerFactory(new OrderedFieldContainerFactory());	// 设置使列顺序是否按照数据库定义的一样
			this.mapping();	// 映射
			dp.start();		// 打开
			arp.start();	// 打开
		
		}catch(RuntimeException e){		// 记录, 再抛出
			log.error(e.getMessage());
			throw e;
		}finally{
			//if(dp != null && dp.)
			// 暂时先不stop 这点泄露不重要
		}
	}
	
	protected void close() {
		if(arp != null) {
			try {
				arp.stop();
				arp = null;
			}catch(Exception e) {
				log.error("关闭ARP出错");
			}
		}
		if(dp != null) {
			try {
				dp.stop();
				dp = null;
			}catch(Exception e) {
				log.error("关闭DP出错");
			}
		}
	}

	public DruidPlugin getDp() {
		return dp;
	}

	public AbstractDatasource setDp(DruidPlugin dp) {
		this.dp = dp;
		return this;
	}

	public ActiveRecordPlugin getArp() {
		return arp;
	}

	public AbstractDatasource setArp(ActiveRecordPlugin arp) {
		this.arp = arp;
		return this;
	}
	
	
	
	
}
